package main

import (
	"fmt"
	"log"
	"os"
	pathpkg "path"
	"strings"

	"../pb"
)

type Leader struct {
	workerNum int
	workers   []*Worker
	idle      chan int
}

type Worker struct {
	client   *Client
	index    int
	basepath string
	feedback chan FeedBack
}

func NewLeader(cli pb.RfdServiceClient) *Leader {
	leader := &Leader{
		workerNum: 5,
		workers:   make([]*Worker, 0),
		idle:      make(chan int),
	}
	for i := 0; i < leader.workerNum; i++ {
		leader.workers = append(leader.workers, &Worker{
			client:   &Client{cli},
			index:    i,
			basepath: "image",
			feedback: make(chan FeedBack),
		})
	}
	return leader
}

func (ld *Leader) Init(basepath string, feedback chan FeedBack) {
	for i := 0; i < ld.workerNum; i++ {
		go func(i int) {
			ld.idle <- i
		}(i)
		ld.workers[i].basepath = basepath
		ld.workers[i].feedback = feedback
	}
}

func (ld *Leader) Dispatch(filePath, latnId string) {
	select {
	case workerId := <-ld.idle:
		go ld.workers[workerId].Work(filePath, latnId, ld.idle)
	}
}

func (ld *Leader) Stop() {
	for ld.workerNum > 0 {
		workerId := <-ld.idle
		ld.workers[workerId] = nil
		ld.workerNum--
	}
}

func (wk *Worker) Work(filePath string, latnId string, idle chan int) {
	s := strings.Split(filePath, "/")
	fileName := s[len(s)-1] + ".tmp"
	path := pathpkg.Join(wk.basepath, fileName)

	// make sure no existed file
	if _, err := os.Stat(path); err == nil {
		log.Printf("[Error] file '%s' exist, remove it.", path)
		os.Remove(path)
	}
	file, err := os.OpenFile(path, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0777)
	if err != nil {
		log.Printf("[Error] 无法打开文件: %s", path)
		wk.SendFeedback(filePath, fmt.Sprintf("Dispatch.Worker.Openfile: %v", err), latnId)
		idle <- wk.index
		return
	}
	// defer file.Close()

	err = wk.client.Download(filePath, latnId, file)

	if err != nil {
		wk.SendFeedback(filePath, fmt.Sprintf("%v", err), latnId)
		file.Close()
		os.Remove(path)
		idle <- wk.index
		return
	}
	file.Close()
	os.Rename(path, strings.TrimRight(path, ".tmp"))
	wk.SendFeedback(filePath, "ok", latnId)
	idle <- wk.index
}

type FeedBack struct {
	file   string
	desc   string
	latnId string
}

func (wk *Worker) SendFeedback(file, description, latnId string) {
	err := FeedBack{
		file:   file,
		desc:   description,
		latnId: latnId,
	}
	wk.feedback <- err
}
